﻿// This code is released under the BSD license.

#if DEBUG

namespace PugLib
{
    using System;
    using System.Diagnostics;
    using System.Globalization;

    public sealed class TestTimer : IComparable<TestTimer>
    {
        private readonly Stopwatch _stopwatch = new Stopwatch();
        private Double _duration;
        private String _testName;

        public TestTimer(String testName)
        {
            _testName = testName;
        }

        public TestTimer(String testName, Boolean startImmediately)
            : this(testName)
        {
            StartIfRequested(startImmediately);
        }

        public Double Duration
        {
            get { return _duration; }
            set { _duration = value; }
        }

        public String TestName
        {
            get { return _testName; }
            set { _testName = value; }
        }

        public String FormattedDuration
        {
            get { return String.Format(CultureInfo.InvariantCulture, "{0:N2}", _duration); }
        }

        #region IComparable<TestTimer> Members

        int IComparable<TestTimer>.CompareTo(TestTimer other)
        {
            return _duration.CompareTo(other._duration);
        }

        #endregion

        private void StartIfRequested(Boolean startImmediately)
        {
            if (startImmediately)
            {
                Start();
            }
        }

        public override String ToString()
        {
            _duration = _stopwatch.Elapsed.TotalSeconds;
            return String.Concat(TestName, " : ", Duration, " seconds");
        }

        public void DebugOutput(Action<String> outputDestination)
        {
            Output(outputDestination);
        }

        public void Output(Action<String> outputDestination)
        {
            outputDestination(ToString());
        }

        public void Start()
        {
            _duration = 0;
            _stopwatch.Start();
        }

        public void Stop()
        {
            _stopwatch.Stop();
            _duration = _stopwatch.Elapsed.TotalSeconds;
        }

        public void StopAndOutput(Action<String> outputDestination)
        {
            Stop();
            Output(outputDestination);
        }

        public void StopAndDebugOutput(Action<String> outputDestination)
        {
            Stop();
            Output(outputDestination);
        }

        public void StopAndDebugOutputConsole()
        {
            StopAndDebugOutput(Console.WriteLine);
        }

        public void Reset()
        {
            _stopwatch.Reset();
        }

        public override Int32 GetHashCode()
        {
            return base.GetHashCode();
        }

        public override Boolean Equals(Object obj)
        {
            TestTimer trd = obj as TestTimer;
            if (trd == null)
            {
                return false;
            }

            return ((0 == String.CompareOrdinal(trd._testName, _testName)) && (_duration == trd._duration));
        }

        public static Boolean operator !=(TestTimer left, TestTimer right)
        {
            return !left.Equals(right);
        }

        public static Boolean operator ==(TestTimer left, TestTimer right)
        {
            return left.Equals(right);
        }

        public static Boolean operator >(TestTimer left, TestTimer right)
        {
            return left._duration > right._duration;
        }

        public static Boolean operator <(TestTimer left, TestTimer right)
        {
            return left._duration < right._duration;
        }

        public Boolean Compare(TestTimer input)
        {
            return this == input;
        }
    }
}

#endif